
#if	!defined( __20090322_DEF_LOGGER_H__ )
#define	__20090322_DEF_LOGGER_H__

#include	<assert.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<iostream>
#include	<fstream>

/**
 *	Log Level
 *	0: Debug
 *	1: Info
 *	2: Warn
 *	3: Error
 *	4: Fatal
 *	5: Close All
 */
//#define	PCELOG_LEVEL	0

//#define	PCELOG_FORMAT_STREAM
//#define	PCELOG_FORMAT_PRINTF

// use stream default
#if	!defined( PCELOG_FORMAT_STREAM )
#if	!defined( PCELOG_FORMAT_PRINTF )
	#define	PCELOG_FORMAT_STREAM
#endif	// PCELOG_FORMAT_PRINTF
#endif	// PCELOG_FORMAT_STREAM

// use 0 level default
#if	!defined( PCELOG_LEVEL )
	#if	defined( PCE_CFG_DEBUG )
		#define		PCELOG_LEVEL	0
	#else
		#define		PCELOG_LEVEL	1
	#endif	//
#endif	// PCELOG_LEVEL

namespace PCE_Lib {
namespace CEnv_Def {
namespace PCE_Lib_CurrentCEnvironment {
namespace Tools {

#if	defined( PCELOG_FORMAT_STREAM )

	#if	defined( PCELOG_FORMAT_PRINTF )
		#error	Define PCELOG_FORMAT_STREAM and PCELOG_FORMAT_PRINTF both
	#endif

	class Logger
	{
	public:
		bool Log2File( ::std::string fname ) throw()
		{
			assert( NotNull( m_Stream ) );
			m_File.open( fname.c_str() );
			if( ! m_File.is_open() ) {
				m_Stream = & ::std::cout;
				return false;
			}
			m_Stream = & m_File;
			return true;
		}
		bool Log2Console( void ) throw()
		{
			assert( NotNull( m_Stream ) );
			m_File.close();
			m_Stream = & ::std::cout;
			return true;
		}
		bool Log2Stderr( void ) throw()
		{
			assert( NotNull( m_Stream ) );
			m_File.close();
			m_Stream = & ::std::cerr;
			return true;
		}
		::std::ostream & Out( void ) throw()
		{
			assert( NotNull( m_Stream ) );
			return * m_Stream;
		}
	public:
		Logger( void ) throw()
			: m_Stream( &::std::cout ), m_File()
		{}
		~Logger( void ) throw() {}
	protected:
		::std::ostream		* m_Stream;
		::std::ofstream		m_File;
	};

	#define	PCELOG_LOG( obj, level, ... )	\
		do {	\
			(obj).Out() << level << ":  " << __VA_ARGS__;	\
			(obj).Out() << ::std::endl;	\
		}while( false )

#elif	defined( PCELOG_FORMAT_PRINTF )

	#if	defined( PCELOG_FORMAT_STREAM )
		#error	Define PCELOG_FORMAT_STREAM and PCELOG_FORMAT_PRINTF both
	#endif

	class Logger
	{
	public:
		bool Log2File( ::std::string fname ) throw()
		{
			assert( NotNull( m_Printf ) );
			if( NotNull( m_File ) ) {
				fclose( m_File );
			}
			m_File = fopen( fname.c_str(), "w" );
			if( IsNull( m_File ) ) {
				m_Printf = stdout;
				return false;
			}
			m_Printf = m_File;
			return true;
		}
		bool Log2Console( void ) throw()
		{
			assert( NotNull( m_Printf ) );
			if( NotNull( m_File ) ) {
				fclose( m_File );
				SetNull( m_File );
			}
			m_Printf = stdout;
			return true;
		}
		bool Log2Stderr( void ) throw()
		{
			assert( NotNull( m_Printf ) );
			if( NotNull( m_File ) ) {
				fclose( m_File );
				SetNull( m_File );
			}
			m_Printf = stderr;
			return true;
		}
		FILE * Out( void ) throw()
		{
			assert( NotNull( m_Printf ) );
			return m_Printf;
		}
	public:
		Logger( void ) throw() : m_Printf( stdout ), m_File() {}
		~Logger( void ) throw()
		{
			if( NotNull( m_File ) ) {
				fclose( m_File );
			}
		}
	protected:
		FILE	* m_Printf;
		FILE	* m_File;
	};

	#define	PCELOG_LOG( obj, level, ... )	\
		do {	\
			assert( NotNull( (obj).Out() ) );	\
			fprintf( (obj).Out(), "%s:  ", level );	\
			fprintf( (obj).Out(), __VA_ARGS__ );	\
			fprintf( (obj).Out(), "\n" );	\
		}while( false )

#else
	#error	Please define PCELOG_FORMAT_STREAM or PCELOG_FORMAT_PRINTF
#endif

#if	PCELOG_LEVEL > 0
	#define	PCELOG_DEBUG( obj, ... )
#else
	#define	PCELOG_DEBUG( obj, ... )	PCELOG_LOG( obj, "[debug]", __VA_ARGS__ )
#endif

#if	PCELOG_LEVEL > 1
	#define	PCELOG_INFO( obj, ... )
#else
	#define	PCELOG_INFO( obj, ... )		PCELOG_LOG( obj, "[info] ", __VA_ARGS__ )
#endif

#if	PCELOG_LEVEL > 2
	#define	PCELOG_WARN( obj, ... )
#else
	#define	PCELOG_WARN( obj, ... )		PCELOG_LOG( obj, "[warn] ", __VA_ARGS__ )
#endif

#if	PCELOG_LEVEL > 3
	#define	PCELOG_ERROR( obj, ... )
#else
	#define	PCELOG_ERROR( obj, ... )	PCELOG_LOG( obj, "[error]", __VA_ARGS__ )
#endif

#if	PCELOG_LEVEL > 4
	#define	PCELOG_FATAL( obj, ... )
#else
	#define	PCELOG_FATAL( obj, ... )	PCELOG_LOG( obj, "[fatal]", __VA_ARGS__ )
#endif

}	// Tools
}	// PCE_Lib_CurrentCEnvironment
}	// CEnv_Def
}	// PCE_Lib

#endif	// __20090322_DEF_LOGGER_H__
